package com.sec.android.app.myfiles.widget;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;

public class RclExpansionHelper {
    public static final int EXPANSION_HEIGHT_AUTO = -1;
    private static final int EXPANSION_HEIGHT_MAX = -2;

    private static final int EXPANSION_ADJUST_UNSPECIFIED = 0;
    public static final int EXPANSION_ADJUST_RESIZE = 1;
    private static final int EXPANSION_ADJUST_PAN = 2;

    private static final int DURATION_ALPHA = 300;
    private static final int DURATION_SCROLL = 500;
    private static final int DURATION_SHORT_SCROLL = 300;

    private static final int STATE_MOVING_UP = 1;
    private static final int STATE_MOVING_DOWN = 2;
    private static final int STATE_SHRUNK = 3;
    private static final int STATE_EXPANDED = 4;
    private static final int STATE_CLOSING = 5;
    private static final int STATE_CLOSED = 6;

    private static final float VELOCITY_OLD_WEIGHT = 0.75f;
    private static final float VELOCITY_NEW_WEIGHT = 0.25f;

    public void updateHeights(int maxHeight, int minHeight) {
        mMaxHeight = maxHeight;
        mMinHeight = minHeight;
    }

    public interface OnExpansionStatusListener {
        void onStart(boolean isExpanded);

        void onProgress(int progress);

        void onFinish(boolean isExpanded);

        void onClose();

        void onMaxHeightChanged(int maxHeight);
    }

    private Activity mActivity;
    private View mRootView;
    private boolean mInitialized;
    private boolean mIntroAnimation = false;

    private ViewGroup mContainer;
    private OnExpansionStatusListener mOnExpansionStatusListener; // for Provider
    private CustomGlobalLayoutListener mOnGlobalLayoutListener;

    private int mContainerId;
    private int mRequestedMaxHeight;
    private int mMinHeight;
    private int mMaxHeight;
    private int mFixedHeight;

    private int mTouchSlopSquare;
    private boolean mIntercept = false;
    private boolean mSwipeFromTop = false;

    private int mState = STATE_SHRUNK;
    private int mInitialValue;

    private float mDownX;
    private float mDownY;

    private boolean mIsLocked = false;
    private ValueAnimator mAnimator;
    private int mLatestNotifyHeight;

    private int mPendingExpansion = 0;

    private int mExpansionMode = EXPANSION_ADJUST_UNSPECIFIED;

    private ViewTreeObserver mRootViewTreeObserver;

    private int mMinimumFlingVelocity;
    private boolean mFlingToClose = true;

    private float mAverageVelocity;
    private float mLastRawY;
    private long mLastEventTime;

    private int mTopSpacing = 0;


    public RclExpansionHelper() {
    }

    public void enable(int containerId, int minHeight, int maxHeight) {
        if (mInitialized) {
            onConfigurationChanged();
            if (mOnExpansionStatusListener != null) {
                if (mState == STATE_EXPANDED && mMaxHeight != maxHeight) {
                    mOnExpansionStatusListener.onMaxHeightChanged(maxHeight - mFixedHeight);
                } else if (mState == STATE_SHRUNK && mMinHeight != minHeight) {
                    if (minHeight == 0) {
                        mOnExpansionStatusListener.onMaxHeightChanged(maxHeight - mFixedHeight);
                    } else {
                        mOnExpansionStatusListener.onMaxHeightChanged(minHeight - mFixedHeight);
                    }
                }
            }

            mContainerId = containerId;
            if (mMinHeight != minHeight) {
                mMinHeight = minHeight;
            }
            if (mRequestedMaxHeight != maxHeight) {
                mRequestedMaxHeight = maxHeight;
                mMaxHeight = -1;
            }
        } else {
            mInitialized = true;
            mContainerId = containerId;
            mMinHeight = minHeight;
            mRequestedMaxHeight = maxHeight;
            mMaxHeight = -1;
        }

        setup();
    }

    public void setFixedHeight(int fixedHeight) {
        mFixedHeight = fixedHeight;

        // setFixedHeight can be triggered before expansion fragment attaching to activity.
        if (mOnExpansionStatusListener != null) {
            if (mState == STATE_EXPANDED) {
                mOnExpansionStatusListener.onMaxHeightChanged(mMaxHeight - mFixedHeight);
            } else if (mState == STATE_SHRUNK) {
                mOnExpansionStatusListener.onMaxHeightChanged(mMinHeight - mFixedHeight);
            }
        }
    }

    private void onConfigurationChanged() {
        if (mContainer == null || mPendingExpansion != 0) {
            return;
        }
        if (mState == STATE_SHRUNK || mState == STATE_MOVING_DOWN) {
            mPendingExpansion = -1;
        }
        if (mState == STATE_EXPANDED || mState == STATE_MOVING_UP) {
            mPendingExpansion = 1;
        }
    }

    public void setActivity(Activity activity) {
        if (mActivity != null) {
            return;
        }
        mActivity = activity;

        setup();
    }

    public void setRootView(View rootView) {
        mRootView = rootView;
        setup();
    }

    public void setup() {
        if (!mInitialized || mActivity == null || mRootView == null) {
            return;
        }

        mContainer = (ViewGroup) mActivity.findViewById(mContainerId);

        if (mContainer == null) {
            return;
        }

        if (mOnGlobalLayoutListener == null) {
            mOnGlobalLayoutListener = new CustomGlobalLayoutListener();
            mContainer.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
            if (mContainer.getWindowVisibility() == View.VISIBLE) {
                mRootViewTreeObserver = mContainer.getViewTreeObserver();
            }
        }

        ViewConfiguration configuration = ViewConfiguration.get(mContainer.getContext().getApplicationContext());
        int touchSlop = configuration.getScaledTouchSlop();
        mTouchSlopSquare = touchSlop * touchSlop;

        mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
    }

    private class CustomGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
        @Override
        public void onGlobalLayout() {
            if (mRootViewTreeObserver == null && mContainer.getWindowVisibility() == View.VISIBLE) {
                mRootViewTreeObserver = mContainer.getViewTreeObserver();
            }
            if (!mInitialized || mContainer.getWindowVisibility() == View.GONE || mContainer.getWindowVisibility() == View.INVISIBLE) {
                if (mRootViewTreeObserver != null) {
                    mRootViewTreeObserver.removeOnGlobalLayoutListener(this);
                }
                mOnGlobalLayoutListener = null;
                mRootViewTreeObserver = null;
                return;
            }

            if (mState == STATE_CLOSED) {
                return;
            }

            int maxHeight = ((ViewGroup) mContainer.getParent()).getMeasuredHeight()
                    - ((ViewGroup) mContainer.getParent()).getPaddingTop()
                    - ((ViewGroup) mContainer.getParent()).getPaddingBottom()
                    - mTopSpacing;
            if (mRequestedMaxHeight != -1) {
                maxHeight = Math.min(mRequestedMaxHeight, maxHeight);
            }

            int minHeight;
            switch (mMinHeight) {
                case EXPANSION_HEIGHT_AUTO:
                    minHeight = mContainer.getMeasuredHeight();
                    break;
                case EXPANSION_HEIGHT_MAX:
                    minHeight = maxHeight;
                    break;
                default:
                    minHeight = mMinHeight;
                    break;
            }

            // For rotation with android:configChanges="orientation:screenChange", mMinHeight can be bigger than mMaxHeight.
            if (minHeight > maxHeight) {
                minHeight = maxHeight;
            }

            if (minHeight != mMinHeight || maxHeight != mMaxHeight) {
                onConfigurationChanged();
                if (mOnExpansionStatusListener != null) {
                    if (mState == STATE_SHRUNK && (mMinHeight != minHeight || minHeight == 0)) {
                        if (minHeight == 0) {
                            mOnExpansionStatusListener.onMaxHeightChanged(maxHeight - mFixedHeight);
                        } else {
                            mOnExpansionStatusListener.onMaxHeightChanged(minHeight - mFixedHeight);
                        }
                    } else if (mState == STATE_EXPANDED && mMaxHeight != maxHeight) {
                        mOnExpansionStatusListener.onMaxHeightChanged(maxHeight - mFixedHeight);
                    } else if (mIntercept && mMaxHeight != maxHeight) {
                        mInitialValue += (maxHeight - mMaxHeight);
                        mLatestNotifyHeight = mInitialValue;
                        mOnExpansionStatusListener.onMaxHeightChanged(maxHeight - mFixedHeight);
                    }
                }
                mMinHeight = minHeight;
                mMaxHeight = maxHeight;

                if (mExpansionMode == EXPANSION_ADJUST_UNSPECIFIED) {
                    if (mMinHeight == 0) {
                        mExpansionMode = EXPANSION_ADJUST_PAN;
                    } else {
                        mExpansionMode = EXPANSION_ADJUST_RESIZE;
                    }
                }

                if (mExpansionMode == EXPANSION_ADJUST_PAN && mRootView.getLayoutParams().height != mMaxHeight) {
                    mRootView.getLayoutParams().height = mMaxHeight;
                    mRootView.requestLayout();
                }

                if (mState == STATE_EXPANDED && mContainer.getLayoutParams().height != mMaxHeight) {
                    mContainer.getLayoutParams().height = mMaxHeight;
                    mContainer.requestLayout();
                } else if (mState == STATE_SHRUNK && mContainer.getLayoutParams().height != mMinHeight) {
                    mContainer.getLayoutParams().height = mMinHeight;
                    mContainer.requestLayout();
                }

                consumePendingExpansion();
            }

            notifyExpansionState();
        }
    }

    private void consumePendingExpansion() {
        boolean animation = mIntroAnimation;

        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
            animation = true;
        }

        int measureHeight = mContainer.getMeasuredHeight();
        if (mPendingExpansion == 0 && measureHeight != mMinHeight && measureHeight != mMaxHeight) {
            if (measureHeight < (mMaxHeight + mMinHeight) / 2) {
                mPendingExpansion = -1;
            } else {
                mPendingExpansion = 1;
            }
        }
        if (mPendingExpansion == -1 && mMinHeight == 0 && measureHeight > 0) {
            mPendingExpansion = 1;
        }

        if (mPendingExpansion != 0) {
            setExpansion(mPendingExpansion == 1, animation);

            if (!animation) {
                mContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        mContainer.getViewTreeObserver().removeOnPreDrawListener(this);

                        return false;
                    }
                });
            }
        }
        mPendingExpansion = 0;
    }

    public boolean onTouchEvent(MotionEvent ev) {
        onTouchEventInternal(ev);
        return true;
    }

    private void onTouchEventInternal(MotionEvent ev) {
        if (mIsLocked || mState == STATE_CLOSING || mState == STATE_CLOSED) {
            return;
        }

        int action = ev.getActionMasked();

        switch(action) {
            case MotionEvent.ACTION_DOWN:
                handleActionDown(ev);
                break;
            case MotionEvent.ACTION_UP:
                handleActionUp();
                break;
            case MotionEvent.ACTION_CANCEL:
                handleActionCancel();
                break;
            case MotionEvent.ACTION_MOVE:
                handleActionMove(ev);
                break;
            default:
                break;
        }
    }

    private void handleActionDown(MotionEvent ev) {
        mLastRawY = ev.getRawY();
        mLastEventTime = ev.getEventTime();
        mAverageVelocity = 0;

        mSwipeFromTop = false;

        mDownX = ev.getRawX();
        mDownY = ev.getRawY();

        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
            mIntercept = true;
            mInitialValue = mContainer.getMeasuredHeight();
        }
    }

    private void handleActionUp() {
        if (mIntercept) {
            mIntercept = false;

            if (mFlingToClose && !mSwipeFromTop) {
                if (mAverageVelocity > mMinimumFlingVelocity
                        && (mState == STATE_SHRUNK || mState == STATE_EXPANDED)
                        && mContainer.getMeasuredHeight() == mMinHeight) {
                    closeAnimation(true);
                    return;
                }
            }
            mSwipeFromTop = false;

            if (mState == STATE_MOVING_DOWN || mState == STATE_MOVING_UP) {
                if (mAverageVelocity <= 0) {
                    startAnimation(true);
                } else {
                    if (mMinHeight == 0) {
                        closeAnimation(true);
                    } else {
                        startAnimation(false);
                    }
                }
            }
        }
    }

    private void handleActionCancel() {
        if (mIntercept) {
            mIntercept = false;
            mSwipeFromTop = false;
            if (mState == STATE_MOVING_UP) {
                startAnimation(true, false);
            } else if (mState == STATE_MOVING_DOWN) {
                if (mMinHeight == 0) {
                    closeAnimation(false);
                } else {
                    startAnimation(false, false);
                }
            }
        }
    }

    private void handleActionMove(MotionEvent ev) {
        if (ev.getEventTime() - mLastEventTime > 0) {
            float v = (ev.getRawY() - mLastRawY) / (ev.getEventTime() - mLastEventTime) * 1000;
            mAverageVelocity = mAverageVelocity * VELOCITY_OLD_WEIGHT + v * VELOCITY_NEW_WEIGHT;
        }

        mLastRawY = ev.getRawY();
        mLastEventTime = ev.getEventTime();
        if (!mIntercept) {
            if (Math.abs(ev.getRawY() - mDownY) < Math.abs(ev.getRawX() - mDownX)) {
                return;
            }

            int distanceY = (int) (ev.getRawY() - mDownY);
            if ((distanceY * distanceY) <= mTouchSlopSquare) {
                return;
            }

            int measureHeight = mContainer.getMeasuredHeight();
            if ((mMinHeight < mMaxHeight && measureHeight == mMinHeight) ||
                    (measureHeight != mMinHeight && measureHeight != mMaxHeight)) {
                mIntercept = true;
            } else if (measureHeight == mMaxHeight && distanceY > 0) {
                mIntercept = true;

                int flags = mActivity.getWindow().getAttributes().flags;
                int resId = mActivity.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
                if ((flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
                        && resId > 0 && mDownY <= mActivity.getApplicationContext().getResources().getDimensionPixelSize(resId)) {
                    mSwipeFromTop = true;
                }
            }

            if (mIntercept) {
                mDownX = ev.getRawX();
                mDownY = ev.getRawY();
                mInitialValue = mLatestNotifyHeight = mContainer.getMeasuredHeight();
                if (mOnExpansionStatusListener != null && mInitialValue != mMaxHeight) {
                    mOnExpansionStatusListener.onMaxHeightChanged(mMaxHeight - mFixedHeight);
                }
            }
        }

        if (mIntercept && !mSwipeFromTop) {
            int distanceY = (int) (ev.getRawY() - mDownY);
            scrollForResize(distanceY);
        }
    }

    private void scrollForResize(int distance) {
        if (distance == 0) return;

        int oldHeight = mContainer.getLayoutParams().height;
        mContainer.getLayoutParams().height = mInitialValue - distance;

        if (mContainer.getLayoutParams().height <= mMinHeight) {
            mContainer.getLayoutParams().height = mMinHeight;
        }

        if (mContainer.getLayoutParams().height >= mMaxHeight) {
            mContainer.getLayoutParams().height = mMaxHeight;
        }
        mContainer.requestLayout();

        if (notifyExpansionProgress()) {
            if (oldHeight > mContainer.getLayoutParams().height) {
                mState = STATE_MOVING_DOWN;
            }
            if (oldHeight < mContainer.getLayoutParams().height) {
                mState = STATE_MOVING_UP;
            }
        }
    }

    private void startAnimation(final boolean expansion) {
        startAnimation(expansion, true);
    }

    private void startAnimation(final boolean expansion, boolean animation) {
        if (!animation) {
            mContainer.getLayoutParams().height = expansion ? mMaxHeight : mMinHeight;
            mContainer.requestLayout();
            notifyExpansionState();
            notifyExpansionEnd(expansion);
            return;
        }

        int measuredHeight = mContainer.getMeasuredHeight();
        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
        }

        if (expansion) {
            if (measuredHeight == mMaxHeight) {
                if (mIntroAnimation) {
                    mIntroAnimation = false;
                }
                notifyExpansionEnd(true);
                return;
            }
            mAnimator = ValueAnimator.ofInt(measuredHeight, mMaxHeight);
        } else {
            if (measuredHeight == mMinHeight) {
                if (mIntroAnimation) {
                    mIntroAnimation = false;
                }
                notifyExpansionEnd(false);
                return;
            }
            mAnimator = ValueAnimator.ofInt(measuredHeight, mMinHeight);
        }

        if (mState == STATE_MOVING_UP || mState == STATE_MOVING_DOWN) {
            mAnimator.setInterpolator(new DecelerateInterpolator());
            mAnimator.setDuration(DURATION_SHORT_SCROLL);
        } else {
            notifyExpansionStart(expansion);
            mAnimator.setInterpolator(new PathInterpolator(.33f, 0f, .1f, 1f)); // SineInOut90
            mAnimator.setDuration(DURATION_SCROLL);
        }

        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mContainer.getLayoutParams().height = (Integer) animation.getAnimatedValue();
                mContainer.requestLayout();

                notifyExpansionProgress();
            }
        });

        mAnimator.addListener(new Animator.AnimatorListener() {
            boolean mNotifyEnd = true;

            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mAnimator = null;
                if (mNotifyEnd) {
                    notifyExpansionEnd(expansion);
                }
                mLatestNotifyHeight = mContainer.getLayoutParams().height;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                mNotifyEnd = false;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        mAnimator.start();

        if (mIntroAnimation) {
            mIntroAnimation = false;
            mContainer.setAlpha(0f);
            mContainer.animate().alpha(1f).setDuration(DURATION_ALPHA).start();
        }
    }

    public void close(boolean animation) {
        closeAnimation(animation);
    }

    private void closeAnimation(boolean animation) {
        if (!animation) {
            if (mInitialized && mOnExpansionStatusListener != null) {
                mOnExpansionStatusListener.onFinish(false);
                mOnExpansionStatusListener.onClose();
                mOnExpansionStatusListener = null;
            }
            mContainer.setVisibility(View.INVISIBLE);
            mContainer.getLayoutParams().height = mMinHeight;
            mContainer.requestLayout();
            mState = STATE_CLOSED;
            return;
        }

        final int preState = mState;
        mState = STATE_CLOSING;

        mContainer.animate().translationY(mMaxHeight - mContainer.getY()).setDuration(DURATION_SHORT_SCROLL).setInterpolator(new DecelerateInterpolator()).setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mContainer.animate().setListener(null);
                mContainer.setTranslationY(0);
                mContainer.setVisibility(View.INVISIBLE);
                mContainer.getLayoutParams().height = mMinHeight;
                mContainer.requestLayout();

                if (mInitialized && mOnExpansionStatusListener != null) {
                    if (preState == STATE_MOVING_DOWN || preState == STATE_MOVING_UP) {
                        mOnExpansionStatusListener.onFinish(false);
                    }
                    mOnExpansionStatusListener.onClose();
                    mOnExpansionStatusListener = null;
                }

                mState = STATE_CLOSED;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        }).start();
    }

    public void lock() {
        mIsLocked = true;
    }

    public void unlock() {
        mIsLocked = false;
    }

    public boolean isLocked() {
        return mIsLocked;
    }

    public boolean isExpanded() {
        boolean bRet = mState == STATE_EXPANDED;

        if (mContainer == null) {
            bRet = false;
        }

        return bRet;
    }

    public boolean setExpansion(boolean expansion) {
        return setExpansion(expansion, true);
    }

    public boolean setExpansion(boolean expansion, boolean animation) {
        mIsLocked = false;
        if (mActivity == null || mMinHeight < 0 || mMaxHeight < 0 || mState == STATE_CLOSING) {
            mPendingExpansion = expansion ? 1 : -1;
            mIntroAnimation = animation;
            return true;
        }
        if (mState == STATE_CLOSED) {
            mIntroAnimation = true;
        }
        mContainer.setVisibility(View.VISIBLE);

        mPendingExpansion = 0;
        startAnimation(expansion, animation);
        return true;
    }

    public void setExpansionStatusListener(OnExpansionStatusListener listener) {
        mOnExpansionStatusListener = listener;
    }

    private void notifyExpansionState() {
        if (mState == STATE_EXPANDED && mContainer.getLayoutParams().height == mMinHeight && mMinHeight < mMaxHeight) {
            notifyExpansionStart(false);
            notifyExpansionEnd(false);
        } else if (mState == STATE_SHRUNK && mContainer.getLayoutParams().height == mMaxHeight) {
            notifyExpansionStart(true);
            notifyExpansionEnd(true);
        }
    }

    private void notifyExpansionStart(boolean isExpand) {
        if (isExpand) {
            mState = STATE_MOVING_UP;
        } else {
            mState = STATE_MOVING_DOWN;
        }

        if (mOnExpansionStatusListener != null) {
            mOnExpansionStatusListener.onStart(isExpand);
        }

        if (mMaxHeight == mMinHeight) {
            return;
        }

        mLatestNotifyHeight = mContainer.getMeasuredHeight();
    }

    private boolean notifyExpansionProgress() {
        if (mMaxHeight == mMinHeight) {
            return false;
        }
        int height = mContainer.getLayoutParams().height;
        if (height == mLatestNotifyHeight) {
            return false;
        }

        if (mState == STATE_SHRUNK || mState == STATE_EXPANDED) {
            notifyExpansionStart(mState == STATE_SHRUNK);
        }

        int notifyValue = (height - mMinHeight) * 100 / (mMaxHeight - mMinHeight);

        mLatestNotifyHeight = height;

        if (mOnExpansionStatusListener != null) {
            mOnExpansionStatusListener.onProgress(notifyValue);
        }

        return true;
    }

    private void notifyExpansionEnd(boolean expand) {
        mState = expand ? STATE_EXPANDED : STATE_SHRUNK;

        if (mOnExpansionStatusListener != null) {
            if (mState == STATE_SHRUNK) {
                mOnExpansionStatusListener.onMaxHeightChanged(mMinHeight - mFixedHeight);
            } else {
                mOnExpansionStatusListener.onMaxHeightChanged(mMaxHeight - mFixedHeight);
            }
        }

        if (mOnExpansionStatusListener != null) {
            mOnExpansionStatusListener.onFinish(expand);
        }
    }

    public void setExpansionMode(int expansionMode) {
        if (mExpansionMode == expansionMode) {
            return;
        }
        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.end();
        }
        mExpansionMode = expansionMode;

        if (mMinHeight >= 0 && mMaxHeight >= 0) {
            switch (expansionMode) {
                case EXPANSION_ADJUST_PAN:
                    if (mRootView.getLayoutParams().height != mMaxHeight) {
                        mRootView.getLayoutParams().height = mMaxHeight;
                        mRootView.requestLayout();
                    }
                    break;
                case EXPANSION_ADJUST_RESIZE:
                    if (mRootView.getLayoutParams().height != mContainer.getLayoutParams().height) {
                        mRootView.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
                        mRootView.requestLayout();
                    }
                    break;

            }
        }
    }

    public void enableFlingToClose(boolean enable) {
        mFlingToClose = enable;
    }

    public void onDestroy() {
        if (mRootViewTreeObserver != null) {
            mRootViewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
            mRootViewTreeObserver = null;
        }
        mOnGlobalLayoutListener = null;
    }

    public void setTopSpacing(int spacing) {
        mTopSpacing = spacing;
    }
}
